home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / port / decsprite / dynloader.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  11.1 KB  |  483 lines

  1.  
  2. /*
  3.  *   DYNAMIC_LOADER.C
  4.  *
  5.  *   Dynamically load specified object module
  6.  *
  7.  *   IDENTIFICATION:
  8.  *   $Header: /private/postgres/src/port/decsprite/RCS/dynloader.c,v 1.7 1991/12/15 02:01:31 glass Exp $
  9.  */
  10.  
  11. #include <stdio.h>
  12. #include <fcntl.h>
  13. #include <sys/exec.h>
  14.  
  15. #ifdef sprite
  16. #define _RELOC_H 1
  17. #include <sym.h>
  18. #endif /* sprite */
  19.  
  20. #include <reloc.h>
  21. #include <syms.h>
  22. #include <symconst.h>
  23. #include <sys/types.h>
  24. #include <sys/stat.h>
  25.  
  26.  
  27. #include "tmp/c.h"
  28. #include "utils/log.h"
  29. #include "utils/fmgr.h"
  30.  
  31. typedef struct reloc        Reloc;
  32.  
  33. char *sbrk();
  34. char *Align();
  35.  
  36. /*
  37.  *  WARNING: the exec header may show dsize = N and bsize = 0 where the
  38.  *  actual format in 'dat' and 'bss' is N - V and V.
  39.  */
  40.  
  41. static struct {
  42.     struct exec ex;
  43.     struct scnhdr txt;
  44.     struct scnhdr dat;
  45.     struct scnhdr bss;
  46. } hdr;
  47.  
  48. /*
  49.  *  Unfortunately, the MIPS proccessor's JAL (jump and link) instruction
  50.  *  only has a 28 bit resolution (26 bits long world aligned).  Therefore,
  51.  *  for dynamically loaded code in the data area (0x1000,0000) to access
  52.  *  routines in the text area, a jump table must be constructed in the
  53.  *  data area that uses the JR (jump register) instruction.
  54.  */
  55.  
  56. typedef struct {
  57.     long  ary[4];
  58.     /*
  59.      *  lui  r14,0xMMMM        0x3C0Exxxx
  60.      *  ori  r14,r14,0xLLLL    0x35CExxxx
  61.      *  jr   r14        0x01C00008  000000rrrrr00000... (r=01110)
  62.      *  nop            0x00000000
  63.      */
  64. } AJMP;
  65.  
  66. #define AJMP0    0x3C0E0000
  67. #define AJMP1    0x35CE0000
  68. #define AJMP2    0x01C00008
  69. #define AJMP3    0x00000000
  70.  
  71. static HDRR shdr;
  72.  
  73. #define a_nscns         ex.ex_f.f_nscns
  74. #define a_symptr        ex.ex_f.f_symptr
  75. #define a_nsyms         ex.ex_f.f_nsyms
  76.  
  77. #define a_tsize         ex.ex_o.tsize
  78. #define a_dsize         ex.ex_o.dsize
  79. #define a_bsize         ex.ex_o.bsize
  80.  
  81. AJMP    *AJmp;
  82.  
  83. DynamicFunctionList *
  84. dynamic_file_load(err, filename, start_address, size)
  85. char **err;
  86. char *filename;
  87. char **start_address;
  88. int *size;
  89.  
  90. {
  91.     int fd;
  92.     int n;
  93.     int a_strsize;
  94.     char *ptr;
  95.     char *p_start;
  96.     char *p_text;
  97.     char *p_data;
  98.     char *p_bss;
  99.     char *p_jmptab;
  100.     char *p_syms;
  101.     char *p_treloc;
  102.     char *p_dreloc;
  103.     char *p_breloc;
  104.     char *p_strs;
  105.     char *p_end;
  106.     DynamicFunctionList *retval, *load_symbols();
  107.  
  108.     bzero(&hdr, sizeof(hdr));
  109.  
  110.     fd = open(filename, O_RDONLY, 0);
  111.     if (fd < 0) {
  112.     *err = "unable to open file";
  113.     return(NULL);
  114.     }
  115.     n = read(fd, &hdr.ex, sizeof(hdr.ex));
  116.     if (n != sizeof(hdr.ex) /*|| N_BADMAG(hdr)*/) {
  117.     *err = "bad object header";
  118.     close(fd);
  119.     return(NULL);
  120.     }
  121.     if (hdr.a_nscns > 3) {
  122.     *err = "expected 3 sections in object hdr";
  123.     close(fd);
  124.     return(NULL);
  125.     }
  126.     read(fd, &hdr.txt, hdr.a_nscns * sizeof(hdr.txt));
  127.     lseek(fd, hdr.a_symptr, 0);
  128.     n = read(fd, &shdr, sizeof(shdr));
  129.     if (n != sizeof(shdr)) {
  130.     *err = "bad sym hdr";
  131.     close(fd);
  132.     return(NULL);
  133.     }
  134.  
  135.     /*
  136.      *  BRK enough for:
  137.      *        a_text
  138.      *        a_data
  139.      *        a_bss
  140.      *        a_syms
  141.      *        a_trsize
  142.      *        a_drsize
  143.      *        and string table
  144.      *
  145.      *  When through relocating, BRK to remove a_syms, a_trsize, a_drsize
  146.      *  NOTE THAT NO CALLS THAT USE MALLOC() MAY BE MADE AFTER THE SBRK!
  147.      */
  148.  
  149.     p_start = ptr = Align(sbrk(0));
  150.     p_text  = ptr;        ptr = p_text + hdr.txt.s_size;
  151.     p_data  = ptr;        ptr = p_data + hdr.dat.s_size;
  152.     p_bss   = ptr;        ptr = p_bss  + hdr.bss.s_size;
  153.     p_jmptab= ptr;        ptr = p_jmptab+ shdr.iextMax * sizeof(AJMP);
  154.     p_syms  = Align(ptr);   ptr = p_syms + shdr.iextMax * sizeof(EXTR);
  155.     p_treloc= Align(ptr);   ptr = p_treloc + hdr.txt.s_nreloc * sizeof(Reloc);
  156.     p_dreloc= Align(ptr);   ptr = p_dreloc + hdr.dat.s_nreloc * sizeof(Reloc);
  157.     p_breloc= Align(ptr);   ptr = p_breloc + hdr.bss.s_nreloc * sizeof(Reloc);
  158.     p_strs  = Align(ptr);   ptr = p_strs + shdr.issExtMax;
  159.     p_end   = Align(ptr);
  160.  
  161.     AJmp = (AJMP *)p_jmptab;
  162.  
  163.     if (brk(p_end) == -1) {
  164.     *err = "brk() failed";
  165.     close(fd);
  166.     return(NULL);
  167.     }
  168.     n = 0;
  169.     n += seekread("text", fd, hdr.txt.s_scnptr, p_text, hdr.txt.s_size);
  170.     n += seekread("data", fd, hdr.dat.s_scnptr, p_data, hdr.dat.s_size);
  171.     n += seekread("bss ", fd, hdr.bss.s_scnptr, p_bss , hdr.bss.s_size);
  172.     n += seekread("syms", fd, shdr.cbExtOffset, p_syms, shdr.iextMax 
  173.                             * sizeof(EXTR));
  174.     n += seekread("trel", fd, hdr.txt.s_relptr, p_treloc,
  175.                     hdr.txt.s_nreloc * sizeof(Reloc));
  176.     n += seekread("drel", fd, hdr.dat.s_relptr, p_dreloc,
  177.                     hdr.dat.s_nreloc * sizeof(Reloc));
  178.     n += seekread("brel", fd, hdr.bss.s_relptr, p_breloc,
  179.                     hdr.bss.s_nreloc * sizeof(Reloc));
  180.     n += seekread("strs", fd, shdr.cbSsExtOffset, p_strs, shdr.issExtMax);
  181.     close(fd);
  182.  
  183.     if (n) {
  184.     *err = "format-read error";
  185.         if (sbrk(0) != p_end) 
  186.         elog(WARN, "dynamic_load: unexpected malloc");
  187.     else
  188.         brk(p_start);    /* restore allocated memory */
  189.     return(NULL);
  190.     }
  191.  
  192.     /*
  193.      *  relocate
  194.      *
  195.      *  n holds cumulative error
  196.      */
  197.  
  198.     {
  199.     EXTR *syms = (EXTR *)p_syms;
  200.     Reloc *reloc;
  201.     Reloc *relend;
  202.  
  203.     n = 0;
  204.     reloc = (Reloc *)p_treloc;
  205.     relend= reloc + hdr.txt.s_nreloc;
  206.     while (reloc < relend) {
  207.         n += relocate(p_text, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  208.         ++reloc;
  209.     }
  210.  
  211.     reloc = (Reloc *)p_dreloc;
  212.     relend= reloc + hdr.dat.s_nreloc;
  213.     while (reloc < relend) {
  214.         n += relocate(p_data, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  215.         ++reloc;
  216.     }
  217.  
  218.     reloc = (Reloc *)p_breloc;
  219.     relend= reloc + hdr.bss.s_nreloc;
  220.     while (reloc < relend) {
  221.         n += relocate(p_bss, reloc, p_syms, p_strs, p_text, p_data,
  222.                       p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
  223.         ++reloc;
  224.     }
  225.     }
  226.     if (n)
  227.     *err = "relocate error";
  228.  
  229.     if (sbrk(0) != p_end) {
  230.     elog(WARN, "unexpected malloc %08lx %08lx", sbrk(0), p_end);
  231.     } else {
  232.         brk(p_syms);    /* destroy non essential data */
  233.     }
  234.     *start_address = p_start;
  235.     *size = (long) (p_syms - p_start);
  236.  
  237.     retval = load_symbols(filename, p_start);
  238.  
  239.     return(retval);
  240. }
  241.  
  242. relocate(base, reloc, symbase, strs, tbase, dbase, bbase, vtbase, vdbase, vbbase)
  243. char *base;
  244. Reloc *reloc;
  245. EXTR *symbase;
  246. char  *strs;
  247. char  *tbase, *dbase, *bbase;
  248. long  vtbase, vdbase, vbbase;
  249. {
  250.     char *address = tbase + reloc->r_vaddr; /* always rel to tbase */
  251.     char *symname;
  252.     unsigned long value;
  253.     short n_type;
  254.  
  255.     fflush(stdout);
  256. #ifdef DYNAMIC_LOADER_DEBUG
  257.     printf("relocate (tdb) %08lx %08lx %08lx addr %08lx\n",
  258.     tbase, dbase, bbase, address
  259.     );
  260. #endif
  261.  
  262.     if (reloc->r_extern == 0) {
  263.     symname = "<internal>";
  264.     switch(reloc->r_symndx) {
  265.     case R_SN_TEXT:
  266. #ifdef DYNAMIC_LOADER_DEBUG
  267.         puts("local text");
  268. #endif
  269.         value = (long)tbase - vtbase;
  270.         break;
  271.     case R_SN_DATA:
  272. #ifdef DYNAMIC_LOADER_DEBUG
  273.         puts("local data");
  274. #endif
  275.         value = (long)dbase - vdbase;
  276.         break;
  277.     case R_SN_SDATA:
  278. #ifdef DYNAMIC_LOADER_DEBUG
  279.         puts("local sdata ???");
  280. #endif
  281.         value = (long)bbase - vbbase;
  282.         break;
  283.     default:
  284.         elog(WARN, "dynamic_loader: don't understand secton type %d",
  285.         reloc->r_symndx
  286.         );
  287.         break;
  288.     }
  289.     } else {
  290.         EXTR *sym = symbase + reloc->r_symndx;
  291.     symname = strs + sym->asym.iss;
  292.     switch(sym->asym.sc) {
  293.     case scText:
  294. #ifdef DYNAMIC_LOADER_DEBUG
  295.         puts("text symb");
  296. #endif
  297.         value = (long)tbase - vtbase;
  298.         break;
  299.     case scData:
  300. #ifdef DYNAMIC_LOADER_DEBUG
  301.         puts("data symb");
  302. #endif
  303.         value = (long)dbase - vdbase;
  304.         break;
  305.     case scBss:
  306. #ifdef DYNAMIC_LOADER_DEBUG
  307.         puts("bss symb");
  308.         puts("????");
  309. #endif
  310.         value = (long)dbase - vbbase;
  311.         break;
  312.     case scUndefined:
  313. #ifdef DYNAMIC_LOADER_DEBUG
  314.         puts("undef symb");
  315. #endif
  316.         {
  317.         FList *fl = ExtSyms;
  318.         char *str = strs + sym->asym.iss;
  319.         AJMP *aj;
  320. #ifdef DYNAMIC_LOADER_DEBUG
  321.         puts(str);
  322. #endif
  323.  
  324.         while (fl->name) {
  325.                 if (strcmp(fl->name, str) == 0)
  326.                 break;
  327.             if (fl->name[0] == '_' && strcmp(fl->name + 1, str) == 0)
  328.             break;
  329.             ++fl;
  330.         }
  331.         if (fl->name == NULL)
  332.             elog(WARN, "dynamic_loader: Illegal ext. symbol %s", str);
  333.         value = (long)fl->func;
  334. #ifdef DYNAMIC_LOADER_DEBUG
  335.         printf("func addr %08lx\n", value);
  336. #endif
  337.  
  338.         aj =  AJmp + reloc->r_symndx;    /* index into jump table */
  339.                         /* create jt entry     */
  340.         aj->ary[0] = AJMP0 | ((value >> 16) & 0xFFFF);
  341.         aj->ary[1] = AJMP1 | (value & 0xFFFF);
  342.         aj->ary[2] = AJMP2;
  343.         aj->ary[3] = AJMP3;
  344.         value = (long)aj;
  345. #ifdef DYNAMIC_LOADER_DEBUG
  346.         printf("Jmp Tab Addr %08lx\n", value);
  347. #endif
  348.         }
  349.         break;
  350.     default:
  351.         elog(WARN, "dynamic_loader: do'na understand storage class %d",
  352.         sym->asym.sc
  353.         );
  354.         break;
  355.     }
  356.     }
  357.  
  358.     switch(reloc->r_type) {
  359.     case R_REFHALF:    /* 1 16 bit reference */
  360.     case R_REFWORD:    /* 2 32 bit reference */
  361.     elog(WARN, "dynamic_loader: reloc type? %d %s",
  362.         reloc->r_type, symname
  363.     );
  364.     break;
  365.     case R_JMPADDR:    /* 3 26 bit jump ref (rel?)  */
  366.     value &= 0x0FFFFFFF;
  367. #ifdef DYNAMIC_LOADER_DEBUG
  368.     printf("ja %08lx %08lx (%08lx)\n", address, value, *(long *)address);
  369. #endif
  370.     *(long *)address += (value >> 2);    /* long words */
  371. #ifdef DYNAMIC_LOADER_DEBUG
  372.     printf("ja address is: %08lx\n", (*(long *)address & 0x03FFFFFF) << 2);
  373. #endif
  374.     break;
  375.     case R_REFHI:    /* 4 high 16 bits        */
  376. #ifdef DYNAMIC_LOADER_DEBUG
  377.     printf("rhi %08lx %08lx (%s)\n", address, value, value);
  378. #endif
  379.     *(short *)(address) += (value >> 16) & 0xFFFF;
  380.     break;
  381.     case R_REFLO:    /* 5 low 16 bits        */
  382. #ifdef DYNAMIC_LOADER_DEBUG
  383.     printf("rlo %08lx %08lx\n", address, value);
  384. #endif
  385.     *(short *)(address) += value & 0xFFFF;
  386.     break;
  387.     case R_GPREL:    /* 6 global pointer relative data item */
  388.     elog(WARN, "dynamic_loader: must compile -G 0!",
  389.         reloc->r_type, symname
  390.     );
  391.     break;
  392.     case R_LITERAL:    /* 7 global pointer relative literal pool item */
  393.     elog(WARN, "dynamic_loader: reloc type? %d %s",
  394.         reloc->r_type, symname
  395.     );
  396.     break;
  397.     default:
  398.     return(-1);
  399.     }
  400.     return(0);
  401. }
  402.  
  403. seekread(seg, fd, offset, ptr, bytes)
  404. char *seg;
  405. int fd;
  406. int offset, bytes;
  407. unsigned char *ptr;
  408. {
  409.     int n;
  410.  
  411.     n = lseek(fd, offset, 0);
  412.     if (n != offset)
  413.     return(-1);
  414.     n = read(fd, ptr, bytes);
  415.     if (n != bytes)
  416.     return(-1);
  417.     return(0);
  418. }
  419.  
  420. char *
  421. Align(padr)
  422. char *padr;
  423. {
  424.     long adr = ((long)padr + 3) & ~3;
  425.     return((char *)adr);
  426. }
  427.  
  428. /*
  429.  * Cheat massively because I can't figure out how to read the symbol table
  430.  * properly, so use system("nm ...") to do it instead.
  431.  */
  432.  
  433. DynamicFunctionList *
  434. load_symbols(filename, entry_addr)
  435.  
  436. char *filename;
  437. int entry_addr;
  438.  
  439. {
  440.     char command[256];
  441.     char line[128];
  442.     char *tmp_file = "/tmp/PG_DYNSTUFF";
  443.     FILE *fp;
  444.     DynamicFunctionList *head, *scanner;
  445.     int entering = 1, func_addr;
  446.     char funcname[16];
  447.  
  448.     sprintf(command, "/usr/bin/nm %s | grep \' T \' > %s", filename, tmp_file);
  449.  
  450.     if (system(command))
  451.     {
  452.         fprintf(stderr, "system() died\n");
  453.     }
  454.  
  455.     fp = fopen(tmp_file, "r");
  456.  
  457.     while (fgets(line, 127, fp) != NULL)
  458.     {
  459.         sscanf(line, "%lx T %s", &func_addr, funcname);
  460.         if (entering)
  461.         {
  462.             head = (DynamicFunctionList *)
  463.                    malloc(sizeof(DynamicFunctionList));
  464.             scanner = head;
  465.             entering = 0;
  466.         }
  467.         else
  468.         {
  469.             scanner->next = (DynamicFunctionList *)
  470.                             malloc(sizeof(DynamicFunctionList));
  471.             scanner = scanner->next;
  472.         }
  473.  
  474.         strcpy(scanner->funcname, funcname);
  475.         scanner->func = (func_ptr) (func_addr + entry_addr);
  476.         scanner->next = NULL;
  477.     }
  478.     fclose(fp);
  479.  
  480.     unlink(tmp_file);
  481.     return(head);
  482. }
  483.